//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package lib.netrxtx;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class TCPPort implements Runnable {
    private Selector dataReady;
    private SocketChannel sch;
    private ServerSocketChannel ssch;
    private String address;
    private int port;
    private TCPPortEventListener evtListener;
    private Thread rcvThread;
    private boolean isStopped;
    private boolean isNotify;
    private List<ByteBuffer> xmtBuffers;
    private List<ByteBuffer> rcvBuffers;
    private OutputStream outs;
    private InputStream ins;
    private int bytesPending;
    private static final int XMTBUFFERMAXLEN = 262144;
    private SocketAddress acceptedAddr = null;

    public TCPPort(String address, int port) {
        this.address = address;
        this.port = port;
        this.isStopped = true;
        this.isNotify = true;
        this.outs = new TCPPort.TCPOutputStream();
        this.ins = new TCPPort.TCPInputStream();
    }

    public void addEventListener(TCPPortEventListener obj) {
        this.evtListener = obj;
    }

    public void removeEventListener() {
        this.evtListener = null;
    }

    public void notifyOnDataAvailable(boolean action) {
        this.isNotify = action;
    }

    public InputStream getInputStream() {
        return this.ins;
    }

    public OutputStream getOutputStream() {
        return this.outs;
    }

    public boolean isConnected() {
        return this.sch == null?false:this.sch.isConnected();
    }

    public void connect() throws Exception {
        if(this.isStopped) {
            try {
                this.dataReady = Selector.open();
                this.sch = SocketChannel.open();
            } catch (IOException var3) {
                ;
            }

            this.bytesPending = 0;
            this.rcvBuffers.clear();
            this.xmtBuffers.clear();

            try {
                if(this.sch.connect(new InetSocketAddress(this.address, this.port))) {
                    this.isStopped = false;
                    this.sch.configureBlocking(false);
                    this.sch.register(this.dataReady, 1);
                    this.rcvThread = new Thread(this, "socketRcvDataProcess");
                    this.rcvThread.start();
                }
            } catch (Exception var2) {
                this.dataReady.close();
                this.sch.close();
                throw var2;
            }
        }

    }

    public void accept() throws IOException {
        if(this.isStopped) {
            try {
                this.dataReady = Selector.open();
                this.ssch = ServerSocketChannel.open();
                if(this.address != null && this.address.length() > 0) {
                    this.ssch.socket().bind(new InetSocketAddress(this.address, this.port));
                } else {
                    this.ssch.socket().bind(new InetSocketAddress(this.port));
                }
            } catch (IOException var3) {
                ;
            }

            this.bytesPending = 0;
            this.rcvBuffers.clear();
            this.xmtBuffers.clear();

            try {
                if((this.sch = this.ssch.accept()) != null) {
                    this.isStopped = false;
                    this.sch.configureBlocking(false);
                    this.sch.register(this.dataReady, 1);
                    this.acceptedAddr = this.sch.getRemoteAddress();
                    this.rcvThread = new Thread(this, "socketRcvDataProcess");
                    this.rcvThread.start();
                }
            } catch (Exception var2) {
                this.dataReady.close();
                if(this.sch != null) {
                    this.sch.close();
                }

                if(var2.getMessage() != null) {
                    throw new IOException(var2.getMessage());
                }

                throw new IOException(var2.getClass().getName() + ": no details descryption");
            }
        }

    }

    public void run() {
        label83:
        while(!this.isStopped) {
            try {
                this.dataReady.selectedKeys().clear();
                this.dataReady.select();
                boolean e = false;
                boolean endOfstream = false;
                Iterator var4 = this.dataReady.selectedKeys().iterator();

                while(true) {
                    SelectionKey key;
                    do {
                        if(!var4.hasNext()) {
                            if(!e) {
                                continue label83;
                            }

                            List key1 = this.rcvBuffers;
                            synchronized(this.rcvBuffers) {
                                this.rcvBuffers.notify();
                            }

                            if(!this.isNotify || this.evtListener == null) {
                                continue label83;
                            }

                            if(!endOfstream) {
                                this.evtListener.tcpPortEvent(new TCPPortEvent(this, 1));
                                continue label83;
                            }

                            this.evtListener.tcpPortEvent(new TCPPortEvent(this, 4));
                            continue label83;
                        }

                        key = (SelectionKey)var4.next();
                        if((key.readyOps() & 1) != 0) {
                            e = true;
                            ByteBuffer rx = ByteBuffer.allocate(65536);
                            int wrb = this.sch.read(rx);
                            if(wrb >= 0) {
                                rx.flip();
                                List xmtLen = this.rcvBuffers;
                                synchronized(this.rcvBuffers) {
                                    this.rcvBuffers.add(rx);
                                }
                            } else {
                                endOfstream = true;
                                e = true;
                                this.isStopped = true;
                            }
                        }
                    } while((key.readyOps() & 4) == 0);

                    this.dataReady.keys().remove(key);
                    List rx1 = this.xmtBuffers;
                    synchronized(this.xmtBuffers) {
                        while(this.xmtBuffers.size() != 0) {
                            ByteBuffer wrb1 = (ByteBuffer)this.xmtBuffers.get(0);
                            int xmtLen1 = wrb1.remaining();
                            this.sch.write(wrb1);
                            xmtLen1 -= wrb1.remaining();
                            this.bytesPending = -xmtLen1;
                            if(wrb1.remaining() != 0) {
                                this.sch.register(this.dataReady, 4);
                                break;
                            }

                            this.xmtBuffers.remove(0);
                        }
                    }
                }
            } catch (IOException var11) {
                this.isStopped = true;
            }
        }

    }

    public void stop() throws IOException {
        if(!this.isStopped) {
            this.isStopped = true;
            this.dataReady.wakeup();

            while(true) {
                List e = this.rcvBuffers;
                synchronized(this.rcvBuffers) {
                    this.rcvBuffers.notify();
                }

                try {
                    if(this.rcvThread != null) {
                        this.rcvThread.join();
                    }
                    break;
                } catch (Exception var3) {
                    System.err.println(var3.getMessage());
                }
            }
        }

        if(this.dataReady != null) {
            this.dataReady.close();
        }

        if(this.sch != null) {
            this.sch.close();
            this.sch = null;
        }

        if(this.ssch != null) {
            this.ssch.close();
            this.ssch = null;
        }

    }

    public String address() {
        return this.address;
    }

    public int port() {
        return this.port;
    }

    public String remote() {
        if(this.acceptedAddr instanceof InetSocketAddress) {
            InetSocketAddress isa = (InetSocketAddress)this.acceptedAddr;
            return isa.getHostString() + ":" + isa.getPort();
        } else {
            return null;
        }
    }

    public class TCPInputStream extends InputStream {
        public TCPInputStream() {
            TCPPort.this.rcvBuffers = new ArrayList();
        }

        public int available() {
            int bytesAvailable = 0;
            synchronized(TCPPort.this.rcvBuffers) {
                for(int i = 0; i < TCPPort.this.rcvBuffers.size(); ++i) {
                    bytesAvailable += ((ByteBuffer)TCPPort.this.rcvBuffers.get(i)).remaining();
                }

                return bytesAvailable;
            }
        }

        public int read() throws IOException {
            byte[] b = new byte[1];
            return this.read(b, 0, b.length);
        }

        public int read(byte[] b) {
            return this.read(b, 0, b.length);
        }

        public int read(byte[] b, int off, int len) {
            if(!TCPPort.this.sch.isConnected() && this.available() == 0) {
                return -1;
            } else if(b == null) {
                throw new NullPointerException();
            } else if(off >= 0 && len >= 0 && len <= b.length - off) {
                if(len == 0) {
                    return 0;
                } else {
                    synchronized(TCPPort.this.rcvBuffers) {
                        if(TCPPort.this.rcvBuffers.size() == 0) {
                            if(!TCPPort.this.sch.isConnected()) {
                                return -1;
                            }

                            try {
                                TCPPort.this.rcvBuffers.wait(5L);
                            } catch (InterruptedException var9) {
                                ;
                            }
                        }
                    }

                    int curReadLength = 0;
                    synchronized(TCPPort.this.rcvBuffers) {
                        int bytes = Math.min(this.available(), len);

                        while(curReadLength < bytes && TCPPort.this.rcvBuffers.size() > 0) {
                            ByteBuffer rdb = (ByteBuffer)TCPPort.this.rcvBuffers.get(0);
                            int maxReadLen = Math.min(rdb.remaining(), bytes - curReadLength);
                            rdb.get(b, off + curReadLength, maxReadLen);
                            curReadLength += maxReadLen;
                            if(rdb.remaining() == 0) {
                                TCPPort.this.rcvBuffers.remove(0);
                            }
                        }

                        return curReadLength;
                    }
                }
            } else {
                throw new IndexOutOfBoundsException();
            }
        }
    }

    public class TCPOutputStream extends OutputStream {
        public TCPOutputStream() {
            TCPPort.this.xmtBuffers = new ArrayList();
        }

        public void write(int b) throws IOException {
            byte[] wb = new byte[]{(byte)b};
            this.write(wb, 0, wb.length);
        }

        public void write(byte[] b) throws IOException {
            this.write(b, 0, b.length);
        }

        public void write(byte[] b, int off, int len) throws IOException {
            if(TCPPort.this.sch != null && TCPPort.this.sch.isConnected()) {
                if(b == null) {
                    throw new NullPointerException();
                } else if(off >= 0 && off <= b.length && len >= 0 && off + len <= b.length && off + len >= 0) {
                    if(len != 0) {
                        synchronized(TCPPort.this.xmtBuffers) {
                            ByteBuffer wrb = ByteBuffer.wrap(b, off, len);
                            if(TCPPort.this.xmtBuffers.size() != 0) {
                                TCPPort.this.bytesPending = TCPPort.this.bytesPending + wrb.remaining();
                                TCPPort.this.xmtBuffers.add(wrb);
                            } else {
                                TCPPort.this.sch.write(wrb);
                                if(wrb.remaining() > 0) {
                                    TCPPort.this.bytesPending = TCPPort.this.bytesPending + wrb.remaining();
                                    TCPPort.this.xmtBuffers.add(wrb);
                                    TCPPort.this.sch.register(TCPPort.this.dataReady, 4);
                                }
                            }

                        }
                    }
                } else {
                    throw new IndexOutOfBoundsException();
                }
            } else {
                throw new IOException("TCPPort: " + TCPPort.this.address + ":" + TCPPort.this.port + ": write failed: Not Connected");
            }
        }
    }
}
